/// \file
/// \brief Provides functionality for voice communications
///
/// \ingroup RAKNET_RAKVOICE
///
/// This file is part of RakNet Copyright 2003 Kevin Jenkins.
/// Usage of Raknet is subject to the appropriate licence agreement.
/// "Shareware" Licensees with Rakkarsoft LLC are subject to the
/// shareware license found at
/// http://www.rakkarsoft.com/shareWareLicense.html
/// "Commercial" Licensees are subject to the commercial license found at
/// http://www.rakkarsoft.com/sourceCodeLicense.html
/// Custom license users are subject to the terms therein.
/// All other users are subject to the GNU General Public
/// License as published by the Free
/// Software Foundation; either version 2 of the License, or (at your
/// option) any later version.

#ifndef __RAK_VOICE_H
#define __RAK_VOICE_H

#include "speex/speex_bits.h"
#include "RakPeerInterface.h"
#include "NetworkTypes.h"
#include "RakNetQueue.h"
#include "SimpleMutex.h"
#include "ArrayList.h"
#include "RakVoiceInterface.h"

/// \internal
/// \ingroup RAKNET_RAKVOICE
/// This is a float in speex 1.0.3 and a short in 1.1.x
typedef short speex_encoding_type;

/// \internal
/// \ingroup RAKNET_RAKVOICE
/// Size of the internal queue to hold sound data.  This should be written to the sound buffer at a fixed rate.
#define RAK_VOICE_INPUT_LIST_BUFFER_SIZE 200

/// \internal
#define MAX_FRAME_SIZE 320

/// \internal
/// \ingroup RAKNET_RAKVOICE
/// \brief Maintains an association between communicating peers
///
/// Each paired player permutation requires its own encoder and decoder
struct CoderStateWithPlayerIDMapStruct
{
	/// Used by speex internally.
	void *decoderState;
	
	/// Used by speex internally.
	void *encoderState;
	
	/// Last time we used this association
	unsigned long lastUsageTime;
	
	/// Remote player id 
	PlayerID playerId;
	
	/// The last packet number we got for decoding
	unsigned short lastReceivedPacketNumber;
	
	/// The next packet number we are going to send out, for encoding
	unsigned short nextPacketNumber;
};

/// \ingroup RAKNET_RAKVOICE
/// \brief RakVoice voice communication library
///
/// RakVoice is a set of functions that uses an instance of RakPeer to transfer, encode, and decode voice packets.
/// I use speex to handle the encoding and decoding part.
/// The sample uses port-audio for record and playback.  You can use anything you want and the system is not tied to port-audio in any way.
/// Bandwidth usage is extraordinarily low, in the hundreds of bytes per second.
/// If you were to use this with RakNet's secure communication capability, you can have secure peer to peer voice communications over the internet.
/// \remark What I've done here is the minimal set of functionality for voice communication.  If you plan to use this in a game, you will probably want to expand on the system.
/// \sa main.cpp
class RakVoice : public RakVoiceInterface
{

public:
	/// Default constructor
	RakVoice();
	
	/// Destructor 
	virtual ~RakVoice();
	
	/// Call this first.	
	///
	/// \param[in] samplingRate Self-explanatory
	/// \param[in] bitsPerSample Self-explanatory
	/// \param[in] _peer The instance of RakPeer to use for sends
	void Init( int samplingRate, int bitsPerSample, RakPeerInterface *_peer );
	
	/// \pre You must have called Init first
	/// Gets the frame size.
	/// \note It is best to send input to EncodeSoundData that matches this frame size
	/// \return The frame size used by the encoder, in bytes
	int GetFrameSize( void ) const;
	
	/// Whenever a player disconnects RakVoice needs to know about it.
	/// Otherwise we will be using old values for our encoding.
	///
	/// \param[in] id PlayerID of the player who has disconnected.
	void Disconnect( PlayerID id );
	
	/// Sets the block size that EncodeSoundPacket will read and
	/// GetSoundPacket will write.  If you don't call this, it will
	/// default to GetFrameSize().  It is reset every call to Init.
	/// \pre Must have called Init first
	/// \param[in] _blockSize The size of each block that you want to process at a time.  Each network packet will have this size before compression.  It must be a multiple of frame_size.  The best _blockSize is what would be compressed to slightly under your MTU.  You can safely assume the compression rate is 50% (actually it's closer to 75%).
	void SetBlockSize( int _blockSize );
	
	/// Frees all memory used.  Call this before shutting down.
	void Deinit( void );
	
	/// Pass your raw sound data to this function.
	/// This function will encode and send in another thread the data as a packet Because of the way encoding works, you cannot broadcast voice data.
	///
	/// \param[in] input A byte array of block size containing the raw voice data.  this must be equal in size to the current blockSize, whatever you passed to SetBlockSize()
	/// \param[in] recipient The targeted peer or UNASSIGNED_PLAYER_ID if you want to send to the server as a client.
	void EncodeSoundPacket( char *input, PlayerID recipient );
	
	/// When you get a packet with the type ID_VOICE_PACKET, pass the packet data and length to this function.
	/// This function will decode the data and put it in the internal queue, or simply relay the data if this is the server and the target is not the server
	///
	/// \param[in] data Packet::data
	/// \param[in] length Packet::length
	/// \sa NetworkTypes.h
	void DecodeAndQueueSoundPacket( char* data, int length );
	
	/// This will get the next sound packet and copy it to output.
	/// By sound packet, I mean decompressed sound data, not network datagram
	/// \param[out] output The resulting raw sound voice data
	/// \param[in] sender Who sent this voice data
	/// \retval true Data was copied to output, of the same length you passed to SetBlockSize
	/// \retval false No sound packets are waiting.
	bool GetSoundPacket( char *output, PlayerID *sender );

	/// Returns the size, in bytes, of the next sound packet, or 0 for nothing left
	/// \return The size, in bytes, of the next sound packet, or 0 for nothing left
	int GetNextSoundPacketSize( void );

	/// This will tell you the total number of bytes waiting to be copied out via the function DecodeAndQueueSoundPacket()
	/// @return Returns the number of remaining byte in the buffer. 
	int GetOutputBufferSize( void );

private:

	/// \internal
	/// Same as init, but for internal use
	void Init( int samplingRate, int bitsPerSample );

	/// \internal
	/// Factory function for a structure, containing information for one player
	CoderStateWithPlayerIDMapStruct* CreateCoderStateWithPlayerIDMapStruct( int samplingRate, PlayerID playerId, bool decoder );
	
	/// \internal
	/// Creates the encoder or decoder state used by speex given the input parameters	
	void *RakVoice::CreateCoderState( int samplingRate, bool decoder );

	/// \internal
	/// Scan the list and return the coder state struct for a given playerID.
	CoderStateWithPlayerIDMapStruct *GetCoderFromPlayerID( unsigned short sr, PlayerID id, bool decoder );
	
	/// \internal
	/// Tracks if Init() succeeded or not.
	bool init;
	
	/// \internal
	/// Encoding calls are buffered to this input list
	/// The thread will then parse this list to actually create the encoded data and send it through the network
	PlayerID targetedSendRecipient[ RAK_VOICE_INPUT_LIST_BUFFER_SIZE ];
	
	/// \internal
	/// Buffered input sound data
	speex_encoding_type inputList[ RAK_VOICE_INPUT_LIST_BUFFER_SIZE ][ MAX_FRAME_SIZE ];
	
	/// \internal
	/// Index into inputList so we know where next to write to
	int writeCursor;
	
	/// \internal
	/// Index into inputList so we know where next to read to
	int readCursor;
	
	/// \internal
	/// bits per sample 
	unsigned char bps;
	
	// SpeexBits bits;
	
	int frame_size;
	
	/// \internal
	// Holds sound packets waiting to be sent to the user via GetSoundPacket()
	struct PCMDataStruct
	{
		/// Sound data
		char *data;
		
		/// Who sent the sound data
		PlayerID sender;
	};


#ifdef _WIN32
	/// Thread that will continually run, processing voice data
	friend unsigned __stdcall rakVoiceThread( LPVOID arguments );
#else
	/// Thread that will continually run, processing voice data
	friend void* rakVoiceThread( void* arguments );
#endif

	/// Queue of PCMDataStruct , which is the data waiting to be copied to the user for playback
	BasicDataStructures::Queue<PCMDataStruct*> PCMQueue;
	
	/// Queue of PCMDataStruct, used to prevent needless reallocations of PCMDataStruct
	BasicDataStructures::Queue<PCMDataStruct*> PCMQueuePool;
	
	/// All the coders and decoders, oen per player
	BasicDataStructures::List<CoderStateWithPlayerIDMapStruct*> coderStateList;
	
	/// Used to lock PCMQueue
	SimpleMutex PCMQueueMutex;
	
	// Used to lock coderStateList
	SimpleMutex coderStateListMutex;
	
	/// Copy of _peer passed to Init()
	RakPeerInterface *peer;

	/// Copy of samplingRate passed to Init()
	unsigned short sampleRate;

	/// Must be a multiple of frame_size
	int blockSize;

	SpeexBits bits;
};

#endif
